package com.example.demo.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.function.Supplier;

public class BucnInvoker<T> {

	public static final Logger log = LoggerFactory.getLogger(BucnInvoker.class);

	static boolean printStackTrace = false;

	T result;

	Throwable expt;

	public static OptResult doOpt(Supplier<OptResult> supplier) {
		BucnInvoker<OptResult> bucnInvoker = new BucnInvoker<>();
		bucnInvoker.invoke(supplier);
		if (bucnInvoker.expt != null) {
			OptResultStack resultTemp = new OptResultStack();
			resultTemp.setResult("0");
			resultTemp.setMsg("操作失败");
			if (bucnInvoker.result == null) {
				bucnInvoker.result = resultTemp;
			}
			if (bucnInvoker.expt instanceof BucnException) {
				bucnInvoker.result.setResult("2");
				bucnInvoker.result.setMsg(bucnInvoker.expt.getMessage());
			}
			if (printStackTrace) {
				String trace = throwToStr(bucnInvoker.expt);
				resultTemp.setStackTrace(trace);
			}
		}
		return bucnInvoker.result;
	}

	public static <M> ListResult<M> doList(Supplier<ListResult<M>> supplier) {
		BucnInvoker<ListResult<M>> bucnInvoker = new BucnInvoker<>();
		bucnInvoker.invoke(supplier);
		if (bucnInvoker.expt != null) {
			ListResultStack<M> resultTemp = new ListResultStack<>();
			resultTemp.setMsg("查询失败");
			resultTemp.setResult("0");
			if (bucnInvoker.result == null) {
				bucnInvoker.result = resultTemp;
			}
			if (bucnInvoker.expt instanceof BucnException) {
				bucnInvoker.result.setResult("2");
				bucnInvoker.result.setMsg(bucnInvoker.expt.getMessage());
			}
			if (printStackTrace) {
				String trace = throwToStr(bucnInvoker.expt);
				resultTemp.setStackTrace(trace);
			}
		}
		return bucnInvoker.result;
	}

	public static <M> EntityResult<M> doEntity(Supplier<EntityResult<M>> supplier) {
		BucnInvoker<EntityResult<M>> bucnInvoker = new BucnInvoker<>();
		bucnInvoker.invoke(supplier);
		if (bucnInvoker.expt != null) {
			EntityResultStack<M> resultTemp = new EntityResultStack<>();
			resultTemp.setMsg("操作失败");
			resultTemp.setResult("0");
			if (bucnInvoker.result == null) {
				bucnInvoker.result = resultTemp;
			}
			if (bucnInvoker.expt instanceof BucnException) {
				bucnInvoker.result.setResult("2");
				bucnInvoker.result.setMsg(bucnInvoker.expt.getMessage());
			}
			if (printStackTrace) {
				String trace = throwToStr(bucnInvoker.expt);
				resultTemp.setStackTrace(trace);
			}
		}
		return bucnInvoker.result;
	}

	public BucnInvoker<T> invoke(Supplier<T> supplier) {
		try {
			result = supplier.get();
		} catch (Throwable e) {
			if (e instanceof BucnException) {
				log.warn("业务异常", e);
			} else {
				log.error("系统异常", e);
			}
			expt = e;
		}
		return this;
	}

	public static String throwToStr(Throwable t) {
		if (t == null) {
			return null;
		}
		try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true)) {
			t.printStackTrace(pw);
			pw.flush();
			sw.flush();
			return sw.getBuffer().toString();
		} catch (IOException e) {
			return "";
		}
	}

	public interface ResultExceptionStack {

		String getStackTrace();

		void setStackTrace(String stackTrace);

		void setResult(String result);

		void setMsg(String msg);
	}

	public static class ListResultStack<T> extends ListResult<T> implements ResultExceptionStack {
		private String stackTrace;

		@Override
		public String getStackTrace() {
			return stackTrace;
		}

		@Override
		public void setStackTrace(String stackTrace) {
			this.stackTrace = stackTrace;
		}
	}

	public static class EntityResultStack<T> extends EntityResult<T> implements ResultExceptionStack {
		private String stackTrace;

		@Override
		public String getStackTrace() {
			return stackTrace;
		}

		@Override
		public void setStackTrace(String stackTrace) {
			this.stackTrace = stackTrace;
		}
	}

	public static class OptResultStack extends OptResult implements ResultExceptionStack {
		private String stackTrace;

		@Override
		public String getStackTrace() {
			return stackTrace;
		}

		@Override
		public void setStackTrace(String stackTrace) {
			this.stackTrace = stackTrace;
		}
	}

	@FunctionalInterface
	interface BucnInvokeConsumer<T> {
		void accept(T t, Throwable expt);
	}

	private static final String NO_MESSAGE_DEFAULT = "service call result no message";

	/**
	 * DML操作模板方法，用于判断变更影响行数
	 *
	 * @param supplier
	 * @return
	 */
	public static int dmlInvoke(Supplier<Integer> supplier) {
		int result = supplier.get();
		if (result <= 0) {
			throw BucnException.create("并发操作,请刷新后重试");
		}
		return result;
	}

	/**
	 * 服务调用 分页类
	 * 
	 * @param supplier
	 * @param <T>
	 * @return
	 */
	public static <T> List<T> referList(Supplier<ListResult<T>> supplier) {
		ListResult<T> result = supplier.get();
		return serviceInvoke(result.getResult(), result.getMsg(), result.getRows());
	}

	/**
	 * 服务调用 分页含页码
	 * 
	 * @param supplier
	 * @param <T>
	 * @return
	 */
	public static <T> ListResult<T> referList2(Supplier<ListResult<T>> supplier) {
		ListResult<T> result = supplier.get();
		return serviceInvoke(result.getResult(), result.getMsg(), result);
	}

	/**
	 * 服务调用 保存类
	 * 
	 * @param supplier
	 * @param <T>
	 */
	public static <T> void referOpt(Supplier<OptResult> supplier) {
		OptResult result = supplier.get();
		serviceInvoke(result.getResult(), result.getMsg(), null);
	}

	/**
	 * 服务调用 实体类
	 * 
	 * @param supplier
	 * @param <T>
	 * @return
	 */
	public static <T> T referEntity(Supplier<EntityResult<T>> supplier) {
		EntityResult<T> result = supplier.get();
		return serviceInvoke(result.getResult(), result.getMsg(), result.getRows());
	}

	static <T> T serviceInvoke(String code, String message, T t) {
		if ("1".equals(code)) {
			return t;
		} else if ("2".equals(code)) {
			throw BucnException.create(message == null ? NO_MESSAGE_DEFAULT : message);
		} else {
			throw new RuntimeException(message == null ? NO_MESSAGE_DEFAULT : message);
		}
	}

}
